package com.example.exceldemo.liteflowComponent.gs;

import com.example.exceldemo.constants.ReqMgrConstants;
import com.example.exceldemo.liteflowComponent.common.GenerateDocuments;
import com.example.exceldemo.model.FunctionInfoDTO;
import com.example.exceldemo.model.ReqInfoDTO;
import com.example.exceldemo.model.TaskStatus;
import com.example.exceldemo.service.ApiService;
import com.example.exceldemo.service.TaskService;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 生成需求功能点拆分表文档组件
 * <p>
 * 该组件负责生成需求的功能点拆分表，通过API获取数据并填充到Excel模板中
 * </p>
 *
 * @author yangwb8
 * @date 2025/5/17 04:06
 */
@LiteflowComponent("three")
@Slf4j
public class GenerateThreeDocuments extends GenerateDocuments {

    /**
     * API服务
     */
    @Autowired
    private ApiService apiService;
    
    /**
     * 任务服务
     */
    @Autowired
    private TaskService taskService;
    
    /**
     * Excel模板标记常量
     */
    private static final String SHEET_NAME = "2、功能点拆分表";
    private static final String DATA_MARKER = "{{data}}";
    private static final String REQ_NAME = "{{reqName}}";
    private static final String SYSTEM = "{{system}}";
    private static final String BUSINESS = "{{business}}";

    /**
     * 处理单个需求的文档生成
     *
     * @param reqInfo 需求信息
     * @param templateDir 模板目录
     * @param reqOutputDir 输出目录
     * @param settings 设置参数
     */
    @Override
    public void processReqDocuments(ReqInfoDTO reqInfo, String templateDir, String reqOutputDir, Map<String, String> settings) {
        log.info("开始生成需求cosmic拆分表");

        // 修改：直接使用模板文件名
        String templateFileName = ReqMgrConstants.TEMPLATE_FUN_LIST;
        Path outputPath = Paths.get(reqOutputDir, getDocName(reqInfo));
        
        try {
            // 处理功能列表信息
            List<FunctionInfoDTO> functionInfoList = processFunctionList(reqInfo);
            StringBuilder funList = new StringBuilder();

            for (FunctionInfoDTO functionInfo : functionInfoList) {
                String name = functionInfo.getName();
                String desc = functionInfo.getDesc();
                String code = functionInfo.getCode();
                funList.append(code).append(".").append(name).append("：").append(desc).append("\n");
            }

            // 构建请求参数
            String name = reqInfo.getReqName();
            String desc = reqInfo.getReqDesc() != null ? reqInfo.getReqDesc() : "";
            String gaizao = funList.toString();
            String itemSize = reqInfo.getItemSize();
            String provCode = reqInfo.getProvCode();
            
            // 构建请求体并发送API请求
            JSONObject requestBody = buildRequestBody(name, desc, gaizao, itemSize,provCode);
            
            // 异步调用API
            String metadata = reqInfo.getReqNo() + ":" + reqInfo.getReqName();
            String taskId = apiService.callApiAsync(requestBody, metadata);
            log.info("异步API请求已提交，任务ID: {}", taskId);
            
            // 等待API响应（轮询任务状态）
            TaskStatus taskStatus = waitForApiResponse(taskId);
            
            if (taskStatus == null || !"COMPLETED".equals(taskStatus.getStatus())) {
                throw new RuntimeException("API请求失败或超时，任务ID: " + taskId);
            }
            
            // 处理API响应数据
            String jsonResponse = taskStatus.getResultData();
            log.info("API响应成功获取");
            
            // 统一使用类路径方式获取模板
            log.info("统一使用类路径加载模板");
            org.springframework.core.io.ClassPathResource classPathResource = new org.springframework.core.io.ClassPathResource("template/gs/" + templateFileName);
            
            // 创建临时文件用于处理
            File tempFile = File.createTempFile("template_", ".xlsx");
            try (InputStream is = classPathResource.getInputStream(); 
                 FileOutputStream fos = new FileOutputStream(tempFile)) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = is.read(buffer)) != -1) {
                    fos.write(buffer, 0, bytesRead);
                }
            }
            
            // 使用临时文件作为模板路径
            fillFromNewJsonFormat(jsonResponse, tempFile.getAbsolutePath(), outputPath.toString(), reqInfo);
            
            // 处理完成后删除临时文件
            if (!tempFile.delete()) {
                log.warn("无法删除临时模板文件: {}", tempFile.getAbsolutePath());
                tempFile.deleteOnExit();
            }
            
            log.info("需求cosmic拆分表生成成功: {}", outputPath);
        } catch (Exception e) {
            log.error("生成需求cosmic拆分表失败", e);
            throw new RuntimeException("生成需求cosmic拆分表失败", e);
        }
    }

    /**
     * 等待API响应（轮询任务状态）
     *
     * @param taskId 任务ID
     * @return 任务状态
     * @throws InterruptedException 如果线程被中断
     */
    private TaskStatus waitForApiResponse(String taskId) throws InterruptedException {
        // 最多等待5分钟
        final int MAX_WAIT_TIME = 5 * 60 * 1000;  // 5分钟（毫秒）
        final int POLL_INTERVAL = 2000;          // 2秒轮询一次
        
        long startTime = System.currentTimeMillis();
        TaskStatus taskStatus = null;
        
        while (System.currentTimeMillis() - startTime < MAX_WAIT_TIME) {
            taskStatus = taskService.getTaskStatus(taskId);
            
            if (taskStatus == null) {
                log.warn("任务不存在: {}", taskId);
                return null;
            }
            
            if ("COMPLETED".equals(taskStatus.getStatus())) {
                return taskStatus;
            }
            
            if ("FAILED".equals(taskStatus.getStatus())) {
                log.error("API任务执行失败: {}, 错误: {}", taskId, taskStatus.getErrorMessage());
                return taskStatus;
            }
            
            // 打印当前进度
            log.debug("API任务进度: {}%, 任务ID: {}", taskStatus.getProgress(), taskId);
            
            // 等待一段时间后再次检查
            Thread.sleep(POLL_INTERVAL);
        }
        
        log.error("API任务执行超时: {}", taskId);
        return taskStatus;
    }

    /**
     * 获取文档名称
     *
     * @param reqInfo 需求信息
     * @return 文档名称
     */
    @Override
    public String getDocName(ReqInfoDTO reqInfo) {
        return "附件2 " + reqInfo.getReqName() + "功能点拆分表.xlsx";
    }

    /**
     * 构建API请求体
     *
     * @param name 需求名称
     * @param desc 需求描述
     * @param gaizao 功能改造内容
     * @param tiao 拆分条数
     * @return 请求体JSON对象
     */
    private JSONObject buildRequestBody(String name, String desc, String gaizao, String tiao,String provCode) {
        JSONObject inputs = new JSONObject();
        inputs.put("name", name);
        inputs.put("desc", desc);
        inputs.put("gaizao", gaizao);
        inputs.put("tiao", tiao);
        inputs.put("provCode", provCode);
        
        JSONObject requestBody = new JSONObject();
        requestBody.put("inputs", inputs);
        requestBody.put("response_mode", "blocking");
        requestBody.put("user", "abc-123");
        
        return requestBody;
    }

    /**
     * 从JSON字符串中提取数据并填充到模板
     *
     * @param jsonStr JSON字符串
     * @param templatePath 模板文件路径
     * @param outputPath 输出文件路径
     * @param reqInfo 需求信息
     * @throws Exception 如果处理过程中发生错误
     */
    public void fillFromNewJsonFormat(String jsonStr, String templatePath, String outputPath, ReqInfoDTO reqInfo) throws Exception {
        // 解析JSON并提取数据
        List<String[]> rowData = extractDataFromJson(jsonStr);
        
        // 填充数据到模板
        fillTemplateWithData(rowData, templatePath, outputPath, reqInfo);
    }
    
    /**
     * 从JSON中提取数据行
     *
     * @param jsonStr JSON字符串
     * @return 数据行列表
     */
    private List<String[]> extractDataFromJson(String jsonStr) {
        JSONObject rootJson = new JSONObject(jsonStr);
        JSONObject data = rootJson.getJSONObject("data");
        JSONObject outputs = data.getJSONObject("outputs");
        String textContent = outputs.getString("text");
        
        // 提取内部JSON字符串
        textContent = textContent.replace("```json\n", "").replace("\n```", "");
        JSONObject innerJson = new JSONObject(textContent);

        log.info("innerJson==:"+innerJson);
        
        // 获取行数据
        JSONArray rowsArray = innerJson.getJSONArray("rows");
        
        // 转换为List<String[]>格式
        List<String[]> rowData = new ArrayList<>();
        for (int i = 0; i < rowsArray.length(); i++) {
            JSONArray row = rowsArray.getJSONArray(i);
            String[] rowValues = new String[row.length()];
            for (int j = 0; j < row.length(); j++) {
                rowValues[j] = row.getString(j);
            }
            rowData.add(rowValues);
        }
        
        // 预处理数据，处理空字符串
        preprocessData(rowData);
        
        return rowData;
    }
    
    /**
     * 预处理数据，填充空值
     * <p>
     * 对于第一列（触发事件）和第二列（功能过程），如果为空，使用上一行的值
     * </p>
     *
     * @param rowData 数据行列表
     */
    private void preprocessData(List<String[]> rowData) {
        String lastEvent = null;
        String lastProcess = null;
        
        for (String[] row : rowData) {
            // 处理第一列（触发事件）
            if (isEmpty(row[0])) {
                if (lastEvent != null) {
                    row[0] = lastEvent;
                }
            } else {
                lastEvent = row[0];
            }
            
            // 处理第二列（功能过程）
            if (isEmpty(row[1])) {
                if (lastProcess != null) {
                    row[1] = lastProcess;
                }
            } else {
                lastProcess = row[1];
            }
        }
    }
    
    /**
     * 将数据填充到模板文件中
     *
     * @param rowData 数据行列表
     * @param templatePath 模板文件路径
     * @param outputPath 输出文件路径
     * @param reqInfo 需求信息
     * @throws Exception 如果处理过程中发生错误
     */
    private void fillTemplateWithData(List<String[]> rowData, String templatePath, String outputPath, ReqInfoDTO reqInfo) throws Exception {
        try (FileInputStream fis = new FileInputStream(templatePath);
             Workbook workbook = WorkbookFactory.create(fis)) {
            
            // 获取工作表
            Sheet sheet = getWorksheet(workbook);
            
            // 查找数据标记位置
            int[] markerPosition = findDataMarker(sheet);
            int dataMarkerRow = markerPosition[0];
            int dataMarkerCol = markerPosition[1];
            
            // 列映射
            int[] columnOffsets = {0, 1, 2, 3, 4, 5}; // 触发事件, 功能过程, 子过程描述, 数据移动类型, 数据组, 数据属性
            
            // 获取样式和垂直合并信息
            Row markerRow = sheet.getRow(dataMarkerRow);
            Map<Integer, CellStyle> columnStyles = getColumnStyles(markerRow, dataMarkerCol, columnOffsets.length);
            Map<Integer, String> verticalMergeCells = getVerticalMergeCells(markerRow, dataMarkerCol);

            // 填充需求基本信息
            getOrCreateCell(markerRow, 0).setCellValue(reqInfo.getReqName());
            getOrCreateCell(markerRow, 1).setCellValue(settings.getOrDefault("system", ReqMgrConstants.DEFAULT_SYSTEM));
            getOrCreateCell(markerRow, 2).setCellValue(reqInfo.getBusiness());
            getOrCreateCell(markerRow, 3).setCellValue(reqInfo.getReqName());
            
            // 创建默认样式
            CellStyle defaultStyle = createDefaultStyle(workbook);
            
            // 清除标记
            clearMarker(markerRow, dataMarkerCol);
            
            // 填充数据
            fillData(sheet, rowData, dataMarkerRow, dataMarkerCol, columnOffsets, columnStyles, verticalMergeCells, defaultStyle);
            
            // 合并单元格
            mergeColumnCells(sheet, dataMarkerRow, dataMarkerRow + rowData.size() - 1, dataMarkerCol); // 触发事件列
            mergeColumnCells(sheet, dataMarkerRow, dataMarkerRow + rowData.size() - 1, dataMarkerCol + 1); // 功能过程列
            
            // 垂直合并左侧单元格
            mergeVerticalCells(sheet, verticalMergeCells.keySet(), dataMarkerRow, rowData.size());
            
            // 保存文件
            saveWorkbook(workbook, outputPath);
        }
    }
    
    /**
     * 获取工作表
     *
     * @param workbook 工作簿
     * @return 工作表
     * @throws Exception 如果找不到指定名称的工作表
     */
    private Sheet getWorksheet(Workbook workbook) throws Exception {
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            if (SHEET_NAME.equals(workbook.getSheetName(i))) {
                return workbook.getSheetAt(i);
            }
        }
        throw new Exception("未找到名为'" + SHEET_NAME + "'的工作表");
    }
    
    /**
     * 查找数据标记位置
     *
     * @param sheet 工作表
     * @return 标记位置数组 [行索引, 列索引]
     * @throws Exception 如果找不到数据标记
     */
    private int[] findDataMarker(Sheet sheet) throws Exception {
        for (int i = 0; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                continue;
            }
            
            for (int j = 0; j < row.getLastCellNum(); j++) {
                Cell cell = row.getCell(j);
                if (cell != null && cell.getCellType() == CellType.STRING && 
                    DATA_MARKER.equals(cell.getStringCellValue())) {
                    log.info("找到{}标记，位置: 行={}, 列={}", DATA_MARKER, i, j);
                    return new int[]{i, j};
                }
            }
        }
        throw new Exception("未找到" + DATA_MARKER + "标记");
    }
    
    /**
     * 获取列样式
     *
     * @param markerRow 标记行
     * @param startCol 开始列
     * @param colCount 列数
     * @return 列样式映射
     */
    private Map<Integer, CellStyle> getColumnStyles(Row markerRow, int startCol, int colCount) {
        Map<Integer, CellStyle> styles = new HashMap<>(colCount + 2);
        for (int j = 0; j < colCount + 2; j++) {
            int targetCol = startCol + j;
            Cell cell = markerRow.getCell(targetCol);
            if (cell != null && cell.getCellStyle() != null) {
                styles.put(targetCol, cell.getCellStyle());
            }
        }
        return styles;
    }
    
    /**
     * 获取需要垂直合并的单元格
     *
     * @param markerRow 标记行
     * @param dataMarkerCol 数据标记列
     * @return 垂直合并单元格映射
     */
    private Map<Integer, String> getVerticalMergeCells(Row markerRow, int dataMarkerCol) {
        Map<Integer, String> cells = new HashMap<>();
        for (int col = 0; col < dataMarkerCol; col++) {
            Cell cell = markerRow.getCell(col);
            if (cell != null) {
                String value = getCellValueAsString(cell);
                if (!isEmpty(value)) {
                    cells.put(col, value);
                }
            }
        }
        return cells;
    }
    
    /**
     * 创建默认单元格样式
     *
     * @param workbook 工作簿
     * @return 默认单元格样式
     */
    private CellStyle createDefaultStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        return style;
    }
    
    /**
     * 清除标记单元格
     *
     * @param markerRow 标记行
     * @param dataMarkerCol 数据标记列
     */
    private void clearMarker(Row markerRow, int dataMarkerCol) {
        Cell markerCell = markerRow.getCell(dataMarkerCol);
        if (markerCell != null) {
            markerCell.setCellValue("");
        }
    }
    
    /**
     * 填充数据到Excel
     *
     * @param sheet 工作表
     * @param rowData 数据行列表
     * @param startRow 开始行
     * @param startCol 开始列
     * @param columnOffsets 列偏移
     * @param columnStyles 列样式
     * @param verticalMergeCells 垂直合并单元格
     * @param defaultStyle 默认样式
     */
    private void fillData(Sheet sheet, List<String[]> rowData, int startRow, int startCol, 
                          int[] columnOffsets, Map<Integer, CellStyle> columnStyles, 
                          Map<Integer, String> verticalMergeCells, CellStyle defaultStyle) {
        for (int i = 0; i < rowData.size(); i++) {
            Row excelRow = getOrCreateRow(sheet, startRow + i);
            String[] cells = rowData.get(i);
            
            // 如果不是第一行，填充左侧需要垂直合并的单元格
            if (i > 0) {
                fillVerticalMergeCells(excelRow, verticalMergeCells, sheet.getRow(startRow), defaultStyle);
            }
            
            // 填充数据
            fillRowData(excelRow, cells, startCol, columnOffsets, columnStyles, defaultStyle);
            
            // 添加CFP值
            addCfpValues(excelRow, startCol, columnOffsets.length, columnStyles, defaultStyle);
        }
    }
    
    /**
     * 获取或创建行
     *
     * @param sheet 工作表
     * @param rowIndex 行索引
     * @return 行对象
     */
    private Row getOrCreateRow(Sheet sheet, int rowIndex) {
        Row row = sheet.getRow(rowIndex);
        return row != null ? row : sheet.createRow(rowIndex);
    }
    
    /**
     * 填充垂直合并单元格内容
     *
     * @param row 行
     * @param cells 单元格内容
     * @param templateRow 模板行
     * @param defaultStyle 默认样式
     */
    private void fillVerticalMergeCells(Row row, Map<Integer, String> cells, Row templateRow, CellStyle defaultStyle) {
        for (Map.Entry<Integer, String> entry : cells.entrySet()) {
            int col = entry.getKey();
            String value = entry.getValue();
            
            Cell cell = getOrCreateCell(row, col);
            cell.setCellValue(value);
            
            // 应用样式
            Cell templateCell = templateRow.getCell(col);
            cell.setCellStyle(templateCell != null && templateCell.getCellStyle() != null ? 
                              templateCell.getCellStyle() : defaultStyle);
        }
    }
    
    /**
     * 填充行数据
     *
     * @param row 行
     * @param data 数据
     * @param startCol 开始列
     * @param columnOffsets 列偏移
     * @param styles 样式
     * @param defaultStyle 默认样式
     */
    private void fillRowData(Row row, String[] data, int startCol, int[] columnOffsets, 
                             Map<Integer, CellStyle> styles, CellStyle defaultStyle) {
        for (int j = 0; j < data.length; j++) {
            int targetCol = startCol + columnOffsets[j];
            Cell cell = getOrCreateCell(row, targetCol);
            cell.setCellValue(data[j]);
            cell.setCellStyle(styles.containsKey(targetCol) ? styles.get(targetCol) : defaultStyle);
        }
    }
    
    /**
     * 添加CFP值
     *
     * @param row 行
     * @param startCol 开始列
     * @param dataColCount 数据列数
     * @param styles 样式
     * @param defaultStyle 默认样式
     */
    private void addCfpValues(Row row, int startCol, int dataColCount, 
                              Map<Integer, CellStyle> styles, CellStyle defaultStyle) {
        // CFP类型列
        int cfpTypeCol = startCol + dataColCount;
        Cell cfpTypeCell = getOrCreateCell(row, cfpTypeCol);
        cfpTypeCell.setCellValue("增加");
        cfpTypeCell.setCellStyle(styles.containsKey(cfpTypeCol) ? styles.get(cfpTypeCol) : defaultStyle);
        
        // CFP值列
        int cfpValueCol = cfpTypeCol + 1;
        Cell cfpValueCell = getOrCreateCell(row, cfpValueCol);
        cfpValueCell.setCellValue("1");
        cfpValueCell.setCellStyle(styles.containsKey(cfpValueCol) ? styles.get(cfpValueCol) : defaultStyle);
    }
    
    /**
     * 获取或创建单元格
     *
     * @param row 行
     * @param colIndex 列索引
     * @return 单元格
     */
    private Cell getOrCreateCell(Row row, int colIndex) {
        Cell cell = row.getCell(colIndex);
        return cell != null ? cell : row.createCell(colIndex);
    }
    
    /**
     * 垂直合并单元格
     *
     * @param sheet 工作表
     * @param columns 列集合
     * @param startRow 开始行
     * @param rowCount 行数
     */
    private void mergeVerticalCells(Sheet sheet, Iterable<Integer> columns, int startRow, int rowCount) {
        for (int col : columns) {
            try {
                sheet.addMergedRegion(new CellRangeAddress(startRow, startRow + rowCount - 1, col, col));
                log.info("垂直合并单元格: 列={}, 行={}-{}", col, startRow, (startRow + rowCount - 1));
            } catch (Exception e) {
                log.warn("警告: 无法垂直合并单元格: 列={} - {}", col, e.getMessage());
            }
        }
    }
    
    /**
     * 合并列中相同值的单元格
     *
     * @param sheet 工作表
     * @param startRow 开始行
     * @param endRow 结束行
     * @param col 列
     */
    private void mergeColumnCells(Sheet sheet, int startRow, int endRow, int col) {
        // 存储每个值的起始行和结束行
        List<int[]> mergeRanges = new ArrayList<>();
        
        // 当前值及其开始行
        String currentValue = null;
        int startIndex = startRow;
        
        // 遍历所有行
        for (int i = startRow; i <= endRow; i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                continue;
            }
            
            Cell cell = row.getCell(col);
            String cellValue = getCellValueAsString(cell);
            
            // 空值处理 - 跳过空值，不进行合并判断
            if (isEmpty(cellValue)) {
                continue;
            }
            
            // 如果是第一个非空值或值发生变化
            if (currentValue == null) {
                currentValue = cellValue;
                startIndex = i;
            } else if (!currentValue.equals(cellValue)) {
                // 如果值变化，合并之前的相同值
                if (i > startIndex + 1) {
                    mergeRanges.add(new int[]{startIndex, i - 1});
                }
                
                // 更新当前值和开始行
                currentValue = cellValue;
                startIndex = i;
            }
        }
        
        // 处理最后一组数据
        if (currentValue != null && endRow > startIndex) {
            mergeRanges.add(new int[]{startIndex, endRow});
        }
        
        // 执行合并
        for (int[] range : mergeRanges) {
            try {
                // 确保合并区域至少包含两行
                if (range[1] > range[0]) {
                    sheet.addMergedRegion(new CellRangeAddress(range[0], range[1], col, col));
                    log.info("合并单元格: {}-{}, 列: {}", range[0], range[1], col);
                }
            } catch (Exception e) {
                log.warn("警告: 无法合并区域 {}:{},{} - {}", range[0], range[1], col, e.getMessage());
            }
        }
    }
    
    /**
     * 保存工作簿
     *
     * @param workbook 工作簿
     * @param outputPath 输出路径
     * @throws IOException 如果IO操作失败
     */
    private void saveWorkbook(Workbook workbook, String outputPath) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(outputPath)) {
            workbook.write(fos);
        }
        log.info("Excel文件生成成功：{}", outputPath);
    }
    
    /**
     * 获取单元格的值并转换为字符串
     *
     * @param cell 单元格
     * @return 单元格值的字符串表示
     */
    private String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }
        
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                return String.valueOf(cell.getNumericCellValue());
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }
    
    /**
     * 检查字符串是否为空
     *
     * @param str 字符串
     * @return 如果字符串为null或空，则返回true
     */
    private boolean isEmpty(String str) {
        return str == null || str.trim().isEmpty();
    }
}
